import smbus2
import time

class SensorReader:
    def __init__(self, i2c_bus=3):
        self.bus = smbus2.SMBus(i2c_bus)
        self.aht20_addr = 0x38
        self.bmp280_addr = 0x77
        self._init_sensors()
    
    def _init_sensors(self):
        """初始化所有传感器"""
        self._aht20_init()
        self.bmp280 = self._bmp280_init()
    
    def _aht20_init(self):
        """初始化AHT20温湿度传感器"""
        self.bus.write_i2c_block_data(self.aht20_addr, 0xBE, [0x08, 0x00])
        time.sleep(0.01)
    
    def _bmp280_init(self):
        """初始化BMP280气压传感器"""
        return BMP280(self.bus, self.bmp280_addr)
    
    def read_all(self):
        """读取所有传感器数据"""
        aht_temp, aht_hum = self._read_aht20()
        bmp_temp, bmp_press = self._read_bmp280()
        
        return {
            "temperature": aht_temp,  # 取两个温度传感器的平均值
            "humidity": aht_hum,
            "pressure": bmp_press
        }
    
    def _read_aht20(self):
        """读取AHT20数据"""
        self.bus.write_i2c_block_data(self.aht20_addr, 0xAC, [0x33, 0x00])
        time.sleep(0.08)
        data = self.bus.read_i2c_block_data(self.aht20_addr, 0x00, 6)
        hum_raw = (data[1] << 12) | (data[2] << 4) | (data[3] >> 4)
        temp_raw = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]
        humidity = (hum_raw / (2**20)) * 100
        temperature = (temp_raw / (2**20)) * 200 - 50
        return round(temperature, 2), round(humidity, 2)
    
    def _read_bmp280(self):
        """读取BMP280数据"""
        raw_temp, raw_press = self.bmp280.read_raw_data()
        bmp_temp, t_fine = self.bmp280.compensate_temperature(raw_temp)
        bmp_press = self.bmp280.compensate_pressure(raw_press, t_fine)
        return bmp_temp, bmp_press

class BMP280:
    """BMP280气压传感器专用类"""
    def __init__(self, bus, address, temp_offset=0):
        self.temp_offset = temp_offset
        self.bus = bus
        self.address = address
        self.dig_T = []
        self.dig_P = []
        self._load_calibration()
    
    def _load_calibration(self):
        calib = self.bus.read_i2c_block_data(self.address, 0x88, 24)
        self.dig_T = [
            (calib[1] << 8) | calib[0],
            (calib[3] << 8) | calib[2],
            (calib[5] << 8) | calib[4]
        ]
        self.dig_P = [
            (calib[7] << 8) | calib[6],
            (calib[9] << 8) | calib[8],
            (calib[11]<< 8) | calib[10],
            (calib[13]<< 8) | calib[12],
            (calib[15]<< 8) | calib[14],
            (calib[17]<< 8) | calib[16],
            (calib[19]<< 8) | calib[18],
            (calib[21]<< 8) | calib[20],
            (calib[23]<< 8) | calib[22]
        ]
    
    def read_raw_data(self):
        self.bus.write_byte_data(self.address, 0xF4, 0x25)
        time.sleep(0.01)
        data = self.bus.read_i2c_block_data(self.address, 0xF7, 6)
        press_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
        temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
        return temp_raw, press_raw
    
    def compensate_temperature(self, raw_temp):
        var1 = ((raw_temp)/16384.0 - self.dig_T[0]/1024.0) * self.dig_T[1]
        var2 = ((raw_temp)/131072.0 - self.dig_T[0]/8192.0) ** 2 * self.dig_T[2]
        t_fine = var1 + var2
        temperature = t_fine / 5120.0 + self.temp_offset
        return round(temperature, 2), t_fine
    
    def compensate_pressure(self, raw_press, t_fine):
        var1 = t_fine/2.0 - 64000.0
        var2 = var1 * var1 * self.dig_P[5] / 32768.0
        var2 = var2 + var1 * self.dig_P[4] * 2.0
        var2 = var2/4.0 + self.dig_P[3] * 65536.0
        var1 = (self.dig_P[2] * var1 * var1 / 524288.0 + self.dig_P[1] * var1) / 524288.0
        var1 = (1.0 + var1 / 32768.0) * self.dig_P[0]
        pressure = 1048576.0 - raw_press
        pressure = (pressure - var2 / 4096.0) * 6250.0 / var1
        var1 = self.dig_P[8] * pressure * pressure / 2147483648.0
        var2 = pressure * self.dig_P[7] / 32768.0
        pressure = pressure + (var1 + var2 + self.dig_P[6]) / 16.0
        return round(pressure / 100.0, 2)